老樣子,又到了喜聞樂見的程式整理環節,我們今天會完成下列事項
主要作用為策略回測,策略參數優化,回測完畢後回傳該股票的獲利與風險報表。
def bt_trainer(stock_index, test_strategy, opt=False, opt_params=None):
    print(stock_index)
    train_df = load_stock(stock_index, start_year=2012, end_year=2015)
    if len(train_df) == 0:
        return pd.DataFrame()
    valid_df = load_stock(stock_index, start_year=2016, end_year=2019)
    if len(valid_df) == 0:
        return pd.DataFrame()
    train_holding_cash = (
        1000
        * train_df.groupby(pd.DatetimeIndex(train_df.index).to_period("M"))
        .nth(0)["Close"]
        .sum()
    )
    valid_holding_cash = (
        1000
        * valid_df.groupby(pd.DatetimeIndex(valid_df.index).to_period("M"))
        .nth(0)["Close"]
        .sum()
    )
    train_bt = Backtest(
        train_df,
        test_strategy,
        cash=train_holding_cash,
        commission=0.004,
        # exclusive_orders=True,
        trade_on_close=True,
    )
    valid_bt = Backtest(
        valid_df,
        test_strategy,
        cash=valid_holding_cash,
        commission=0.004,
        # exclusive_orders=True,
        trade_on_close=True,
    )
    if opt:
        train_result = train_bt.optimize(**opt_params)
        valid_result = valid_bt.run(**train_result["_strategy"].params)
    else:
        train_result = train_bt.run()
        valid_result = valid_bt.run()
    result = train_result.copy()
    result["stock_id"] = stock_index
    result["Strategy"] = test_strategy.__name__
    result["Params"] = result["_strategy"].params
    result["Train Return (Ann.) [%]"] = train_result["Return (Ann.) [%]"]
    result["Train Max. Drawdown [%]"] = train_result["Max. Drawdown [%]"]
    result["Train Sharpe Ratio"] = train_result["Sharpe Ratio"]
    result["Train SQN"] = train_result["SQN"]
    result["Valid Return (Ann.) [%]"] = valid_result["Return (Ann.) [%]"]
    result["Valid Max. Drawdown [%]"] = valid_result["Max. Drawdown [%]"]
    result["Valid Sharpe Ratio"] = valid_result["Sharpe Ratio"]
    result["Valid SQN"] = valid_result["SQN"]
    # result["Backtest Train"] = train_bt
    # result["Backtest Valid"] = valid_bt
    opt_str = "opt" if opt else "std"
    plot_dir = f"./data/Strategy/{test_strategy.__name__}/{opt_str}"
    Path(plot_dir).mkdir(parents=True, exist_ok=True)
    valid_bt.plot(
        filename=plot_dir + f"/{stock_index}.html",
        open_browser=False,
    )
    df = result.to_frame().transpose()
    return df
def report_generate(frames, test_strategy, opt):
    final_df = pd.concat(frames).reset_index(drop=True)
    final_df = final_df.loc[
        final_df["Duration"] == final_df["Duration"].max()
    ].reset_index(drop=True)
    stock_name = pd.read_csv(
        "data/stock_id.csv", dtype={"stock_id": str, "stock_name": str}
    )
    profit_df = final_df.merge(stock_name, on="stock_id")
    report_df = profit_df[
        [
            "stock_id",
            "stock_name",
            "Train Return (Ann.) [%]",
            "Train Max. Drawdown [%]",
            "Train Sharpe Ratio",
            "Train SQN",
            "Valid Return (Ann.) [%]",
            "Valid Max. Drawdown [%]",
            "Valid Sharpe Ratio",
            "Valid SQN",
        ]
    ]
    opt_str = "opt" if opt else "std"
    report_dir = f"./data/Strategy/{test_strategy.__name__}/{opt_str}"
    Path(report_dir).mkdir(parents=True, exist_ok=True)
    report_df.to_csv(
        report_dir + "/Report.csv",
        index=False,
        header=True,
    )
    report_df = pd.read_csv(report_dir + "/Report.csv", dtype={"stock_id": str})
    return report_df
回測的部分差不多結束了,明天會測試幾個常見的幾種策略。